import Necessity from '../enums/PhysicalTypeNecessity.js';
import PhysicalType from '../entity/PhysicalType.js';
import {
    STRING_CLASS_NAME,
    LONG_CLASS_NAME,
    INTEGER_CLASS_NAME,
    ENUM_CLASS_NAME,
    MAP_CLASS_NAME,
    LIST_CLASS_NAME,
    SET_CLASS_NAME,
    COLLECTION_CLASS_NAME,
} from './dependency-lib-jdk.js';

const common = [];

common.push(new PhysicalType('varchar', Necessity.REQUIRED, 30, Necessity.NONE, 0,
    ['\'\''], [STRING_CLASS_NAME],
    ['java.lang.*', 'long', 'int', 'java.math.BigDecimal', 'double', 'float', 'java.util.*', 'java.time.*']));

common.push(new PhysicalType('char', Necessity.REQUIRED, 1, Necessity.NONE, 0,
    ['\'\''], [ENUM_CLASS_NAME, 'java.lang.Character', 'char'],
    ['java.lang.*', 'long', 'int', 'java.math.BigDecimal', 'double', 'float', 'java.time.*']));

common.push(new PhysicalType('bigint', Necessity.NONE, 0, Necessity.NONE, 0,
    [], [LONG_CLASS_NAME, 'long'],
    ['java.math.BigInteger']));

common.push(new PhysicalType('int', Necessity.NONE, 0, Necessity.NONE, 0,
    [], [INTEGER_CLASS_NAME, 'int'],
    ['java.lang.Short', 'short', 'java.lang.Character', 'char', 'java.lang.Byte', 'byte', 'java.math.BigInteger']));

common.push(new PhysicalType('decimal', Necessity.REQUIRED, 11, Necessity.REQUIRED, 2,
    [], ['java.math.BigDecimal'],
    [LONG_CLASS_NAME, 'long', INTEGER_CLASS_NAME, 'int', 'java.lang.Double', 'double', 'java.lang.Float', 'float',
        'java.lang.Short', 'short', 'java.lang.Character', 'char', 'java.lang.Byte', 'byte', 'java.math.BigInteger']));

common.push(new PhysicalType('bit', Necessity.OPTIONAL, 1, Necessity.NONE, 0,
    [], ['java.lang.Boolean', 'boolean']));

common.push(new PhysicalType('date', Necessity.NONE, 0, Necessity.NONE, 0,
    [], ['java.time.LocalDate']));

common.push(new PhysicalType('time', Necessity.NONE, 0, Necessity.NONE, 0,
    [], ['java.time.LocalTime']));

common.push(new PhysicalType('text', Necessity.NONE, 0, Necessity.NONE, 0,
    ['\'\''], [],
    [STRING_CLASS_NAME, LIST_CLASS_NAME, SET_CLASS_NAME, MAP_CLASS_NAME, COLLECTION_CLASS_NAME]));

common.push(new PhysicalType('double', Necessity.REQUIRED, 17, Necessity.REQUIRED, 2,
    [], ['java.lang.Double', 'double']));

common.push(new PhysicalType('float', Necessity.REQUIRED, 7, Necessity.REQUIRED, 2,
    [], ['java.lang.Float', 'float']));

const MYSQL = [];
MYSQL.push(...common);
// varchar和char添加uuid()作为默认值选项
MYSQL[0] = MYSQL[0].clone(type => {
    type.defaultValues.push('uuid()');
});
MYSQL[1] = MYSQL[1].clone(type => {
    type.defaultValues.push('uuid()');
});

// 将datetime插入到date前
MYSQL.splice(MYSQL.length - 5, 0, new PhysicalType('datetime', Necessity.NONE, 0, Necessity.NONE, 0,
    ['current_timestamp', 'now()'], ['java.time.LocalDateTime', 'java.util.Date']));

// 将timestamp插入到text前
MYSQL.splice(MYSQL.length - 3, 0, new PhysicalType('timestamp', Necessity.NONE, 0, Necessity.NONE, 0,
    ['current_timestamp', 'now()'], ['java.time.Instant'], ['java.util.Date']));

const H2 = [];
// H2与MySQL一致
H2.push(...MYSQL);

const POSTGRESQL = [];
POSTGRESQL.push(...common);
POSTGRESQL[0] = POSTGRESQL[0].clone(type => {
    type.defaultValues.push('uuid_generate_v4()');
});
POSTGRESQL[1] = POSTGRESQL[1].clone(type => {
    type.defaultValues.push('uuid_generate_v4()');
});

// 将timestamp插入到text前
POSTGRESQL.splice(POSTGRESQL.length - 3, 0, new PhysicalType('timestamp', Necessity.NONE, 0, Necessity.NONE, 0,
    ['current_timestamp', 'now()'], ['java.time.LocalDateTime', 'java.util.Date', 'java.time.Instant']));

const ORACLE = [];
ORACLE.push(...common);
ORACLE[0] = ORACLE[0].clone(type => {
    type.name = 'varchar2';
    type.defaultValues.push('sys_guid()');
});
ORACLE[1] = ORACLE[1].clone(type => {
    type.defaultValues.push('sys_guid()');
});
// 将timestamp插入到text前
ORACLE.splice(ORACLE.length - 3, 0, new PhysicalType('timestamp', Necessity.NONE, 0, Necessity.NONE, 0,
    ['sysdate'], ['java.time.LocalDateTime', 'java.util.Date', 'java.time.Instant']));

const SQL_SERVER = [];
SQL_SERVER.push(...common);
SQL_SERVER[0] = SQL_SERVER[0].clone(type => {
    type.defaultValues.push('newid()');
});
SQL_SERVER[1] = SQL_SERVER[1].clone(type => {
    type.defaultValues.push('newid()');
});
// 将datetime插入到date前
SQL_SERVER.splice(SQL_SERVER.length - 5, 0, new PhysicalType('datetime', Necessity.NONE, 0, Necessity.NONE, 0,
    ['getdate()', 'sysdatetime()'], ['java.time.LocalDateTime', 'java.util.Date', 'java.time.Instant']));

const all = {MYSQL, H2, POSTGRESQL, ORACLE, SQL_SERVER};

export default all;

export const getDefaultPhysicalType = function (physicalTypes, logicType, arrayed = false) {
    if (logicType) {
        if (typeof physicalTypes === 'string') {
            physicalTypes = all[physicalTypes];
        }
        if (Array.isArray(physicalTypes)) {
            if (logicType === MAP_CLASS_NAME || arrayed) { // Map和数组一律被视为字符串，因为后续会做转换映射
                logicType = STRING_CLASS_NAME;
            }
            for (let physicalType of physicalTypes) {
                if (physicalType.defaultClasses.includes(logicType)) {
                    return physicalType;
                }
            }
        }
    }
    return undefined;
}

export const getDefaultValues = function (databaseVendor, physicalTypeName) {
    let physicalType = all[databaseVendor].find(pt => pt.name === physicalTypeName);
    if (physicalType) {
        return physicalType.defaultValues;
    }
    return [];
}
